import { GEOMETRYTYPE } from '../const'
import { uuid } from '../utils/common'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import Feature from 'ol/Feature'
import { Point, LineString, Polygon } from 'ol/geom'
import { Fill, Circle, Stroke, Style } from 'ol/style'
import { fromLonLat } from 'ol/proj'
import EditTool from './edit'
import SnapTool from './snap'
import {
  filterDuplicatePoints,
  getCircleCoords,
  toggleDoubleZoom
} from '../utils/map'

let drawToolThat = null

/**
 * 初始化构造函数
 * @param {ol.Map} map - map
 * @param {boolean} [isEditTool = true] - 是否编辑工具
 */
class DrawTool {
  constructor (map, options) {
    this._map = map

    this._options = Object.assign({
      drawEnd (feature) {
        // console.log(feature)
      }
    }, options)

    // 是否绘制
    this._isDraw = false

    // 绘制类型，取值于GEOMETRYTYPE
    this._drawType = ''

    // 记录绘制时候的点
    this._coordinates = []

    // 绘制时候的feature
    this._drawFeature = null

    // vector source & layer
    this._vectorSource = null
    this._vectorLayer = null

    // 捕捉工具
    this._snapTool = null

    // 编辑工具
    this._editTool = null

    // 当前绘制id
    this._drawId = ''

    // 初始化，完成vector图层的创建和添加，编辑工具和捕捉工具的初始化
    this._init()
  }

  /**
   * 切换编辑状态
   * @param {boolean} isEdit - 切换编辑状态
   */
  toggleEdit (isEdit) {
    drawToolThat._editTool.toggleEdit(isEdit)
  }

  /**
   * 获取编辑工具
   * @return {EditTool} - 编辑工具
   */
  getEditTool () {
    return drawToolThat._editTool
  }

  /**
   * 切换捕捉状态
   * @param {boolean} isSnap - 切换捕捉状态
   */
  toggleSnap (isSnap) {
    this._snapTool.setActive(isSnap)
  }

  /**
   * 清除绘制
   */
  clear () {
    this._vectorSource.clear()
  }

  // 初始化，完成vector图层的创建和添加，捕捉工具和编辑工具的初始化
  _init () {
    drawToolThat = this
    drawToolThat._vectorSource = new VectorSource()
    drawToolThat._vectorLayer = new VectorLayer({
      source: drawToolThat._vectorSource,
      style: drawToolThat._styleFunction
    })
    this._map.addLayer(this._vectorLayer)

    drawToolThat._snapTool = new SnapTool(this._map, this._vectorSource)
    drawToolThat._editTool = new EditTool(this._map, this._vectorSource, this._vectorLayer, this._snapTool)
  }

  // 样式方法
  _styleFunction (feat) {
    let styles = []
    // 默认样式
    styles.push(new Style({
      fill: new Fill({
        color: 'rgba(255, 0, 0, 0.1)'
      }),
      stroke: new Stroke({
        color: '#ff0000',
        width: 3
      }),
      image: new Circle({
        radius: 6,
        fill: new Fill({
          color: '#ff0000'
        })
      })
    }))
    const geomType = feat.getGeometry().getType()
    if (geomType !== 'Point') {
      const getCoordsPointStyle = function (coords) {
        let res = []
        coords.forEach(coord => {
          res.push(new Style({
            geometry: new Point(coord),
            image: new Circle({
              radius: 3,
              stroke: new Stroke({
                color: '#ff0000',
                width: 1
              }),
              fill: new Fill({
                color: '#ffffff'
              })
            })
          }))
        })
        return res
      }
      const geometryType = feat.get('geometryType')
      if (geometryType === GEOMETRYTYPE.CIRCLE) { // 圆特殊处理
        const center = feat.get('center')
        const point = feat.get('point')
        const line = [center, point]
        styles.push(new Style({
          geometry: new LineString(line),
          stroke: new Stroke({
            color: '#ff0000',
            width: 1
          })
        }))
        styles.push(new Style({
          geometry: new Point(point),
          image: new Circle({
            radius: 3,
            stroke: new Stroke({
              color: '#ff0000',
              width: 1
            }),
            fill: new Fill({
              color: '#ffffff'
            })
          })
        }))
        styles.push(new Style({
          geometry: new Point(center),
          image: new Circle({
            radius: 4,
            stroke: new Stroke({
              color: '#ff0000',
              width: 1
            }),
            fill: new Fill({
              color: '#ffffff'
            })
          })
        }))
      } else {
        let coords = feat.getGeometry().getCoordinates()
        switch (geomType) {
          case 'LineString': {
            styles = [...styles, ...getCoordsPointStyle(coords)]
            break
          }
          case 'MultiLineString': {
            coords.forEach(_coords => {
              styles = [...styles, ...getCoordsPointStyle(_coords)]
            })
            break
          }
          case 'Polygon': {
            coords.forEach(_coords => {
              _coords.length = _coords.length - 1
              styles = [...styles, ...getCoordsPointStyle(_coords)]
            })
            break
          }
          case 'MultiPolygon': {
            coords.forEach(_coords => {
              _coords.forEach(__coords => {
                styles = [...styles, ...getCoordsPointStyle(__coords)]
              })
            })
          }
        }
      }
    }
    return styles
  }

  /**
   * 绘制，取值于 GEOMETRYTYPE
   * @param {String} type - 绘制类型
   */
  draw (type) {
    switch (type) {
      case GEOMETRYTYPE.POINT: {
        this.drawPoint()
        break
      }
      case GEOMETRYTYPE.LINESTRING: {
        this.drawLineString()
        break
      }
      case GEOMETRYTYPE.POLYGON: {
        this.drawPolygon()
        break
      }
      case GEOMETRYTYPE.RECTANGLE: {
        this.drawRectangle()
        break
      }
      case GEOMETRYTYPE.CIRCLE: {
        this.drawCircle()
        break
      }
    }
  }

  /**
   * 绘制点
   */
  drawPoint () {
    this._endDraw()
    this._drawType = GEOMETRYTYPE.POINT
    this._startDraw()
  }

  /**
   * 绘制线
   */
  drawLineString () {
    this._endDraw()
    this._drawType = GEOMETRYTYPE.LINESTRING
    this._startDraw()
  }

  /**
   * 绘制面
   */
  drawPolygon () {
    this._endDraw()
    this._drawType = GEOMETRYTYPE.POLYGON
    this._startDraw()
  }

  /**
   * 绘制矩形
   */
  drawRectangle () {
    this._endDraw()
    this._drawType = GEOMETRYTYPE.RECTANGLE
    this._startDraw()
  }

  /**
   * 绘制圆
   */
  drawCircle () {
    this._endDraw()
    this._drawType = GEOMETRYTYPE.CIRCLE
    this._startDraw()
  }

  // 开始绘制
  _startDraw () {
    // 禁用编辑和双击放大，并设置鼠标手势
    drawToolThat._editTool.toggleEdit(false)
    toggleDoubleZoom(this._map, false)
    this._map.getTargetElement().style.cursor = 'crosshair'

    this._isDraw = true
    this._drawId = uuid()

    // 绑定map事件
    this._map.on('click', this._clickEvent)
    this._map.on('pointermove', this._pointerMoveEvent)
    this._map.on('dblclick', this._dblClickEvt)
  }

  // map click事件
  _clickEvent (e) {
    if (!drawToolThat || !drawToolThat._isDraw) return

    // 获取捕捉点
    let coordinate = e.coordinate
    const snapCoordinate = drawToolThat._snapTool ? drawToolThat._snapTool.getSnapPoint(coordinate) : []
    coordinate = snapCoordinate.length === 0 ? coordinate : fromLonLat(snapCoordinate)
    drawToolThat._coordinates.push(coordinate)

    switch (drawToolThat._drawType) {
      case GEOMETRYTYPE.LINESTRING: {
        if (drawToolThat._coordinates.length > 1) {
          drawToolThat._addLine2Map(drawToolThat._coordinates)
        }
        break
      }
      case GEOMETRYTYPE.POLYGON: {
        if (drawToolThat._coordinates.length > 2) {
          const coords = drawToolThat._coordinates.concat([drawToolThat._coordinates[0]])
          drawToolThat._addPolygon2Map(coords)
        }
        break
      }
      case GEOMETRYTYPE.RECTANGLE: {
        // 结束绘制
        if (drawToolThat._coordinates.length === 2) {
          let coords = drawToolThat._coordinates
          const [x0, y0] = coords[0]
          const [x1, y1] = coords[1]
          coords = [
            coords[0],
            [x1, y0],
            coords[1],
            [x0, y1],
            coords[0]
          ]
          drawToolThat._addRectangle2Map(coords)
          drawToolThat._endDraw()
        }
        break
      }
      case GEOMETRYTYPE.CIRCLE: {
        let coords = drawToolThat._coordinates
        if (coords.length === 2) {
          drawToolThat._addCircle2Map(coords[0], coords[1])
          drawToolThat._endDraw()
        }
        break
      }
      case GEOMETRYTYPE.POINT: {
        drawToolThat._addPoint2Map()
        drawToolThat._endDraw()
        break
      }
    }
  }

  // map 鼠标移动事件
  _pointerMoveEvent (e) {
    if (drawToolThat._isDraw) {
      // 深拷贝坐标点
      let coords = drawToolThat._coordinates.concat([])
      // 获取捕捉点
      let coordinate = e.coordinate
      const snapCoordinate = drawToolThat._snapTool ? drawToolThat._snapTool.getSnapPoint(coordinate) : []
      coordinate = snapCoordinate.length === 0 ? coordinate : fromLonLat(snapCoordinate)
      coords.push(coordinate)

      switch (drawToolThat._drawType) {
        case GEOMETRYTYPE.LINESTRING: {
          if (coords.length > 1) {
            drawToolThat._addLine2Map(coords, true)
          }
          break
        }
        case GEOMETRYTYPE.POLYGON: {
          if (coords.length === 2) {
            drawToolThat._addLine2Map(coords, true)
          } else if (coords.length > 2) {
            coords = coords.concat([coords[0]])
            drawToolThat._addPolygon2Map(coords, true)
          }
          break
        }
        case GEOMETRYTYPE.RECTANGLE: {
          if (coords.length === 2) {
            const [x0, y0] = coords[0]
            const [x1, y1] = coords[1]
            coords = [
              coords[0],
              [x1, y0],
              coords[1],
              [x0, y1],
              coords[0]
            ]
            drawToolThat._addPolygon2Map(coords, true)
          }
          break
        }
        case GEOMETRYTYPE.CIRCLE: {
          if (coords.length === 2) {
            drawToolThat._addCircle2Map(coords[0], coords[1], true)
          }
          break
        }
      }
    }
  }

  // map dblclick事件
  _dblClickEvt (e) {
    drawToolThat._endDraw()
  }

  // 结束绘制
  _endDraw () {
    if (drawToolThat._coordinates.length === 0) return
    drawToolThat._map.getTargetElement().style.cursor = 'default'
    // 双击会产生重复点，所以进行处理
    drawToolThat._coordinates = filterDuplicatePoints(drawToolThat._coordinates)

    // 将绘制的结果在地图上展示
    switch (drawToolThat._drawType) {
      case GEOMETRYTYPE.LINESTRING: {
        if (drawToolThat._coordinates.length > 1) {
          drawToolThat._addLine2Map(drawToolThat._coordinates)
        }
        break
      }
      case GEOMETRYTYPE.POLYGON: {
        if (drawToolThat._coordinates.length > 2) {
          drawToolThat._coordinates = drawToolThat._coordinates.concat([drawToolThat._coordinates[0]])
          drawToolThat._addPolygon2Map(drawToolThat._coordinates)
        }
        break
      }
    }

    // 绘制完成后的回调
    if (drawToolThat._drawType !== GEOMETRYTYPE.POINT) drawToolThat._options.drawEnd.call(this, drawToolThat._drawFeature)

    // 解绑map事件
    drawToolThat._map.un('click', drawToolThat._clickEvent)
    drawToolThat._map.un('pointermove', drawToolThat._clickEvent)
    drawToolThat._map.un('dblclick', drawToolThat._dblClickEvt)

    // 重置变量
    drawToolThat._isDraw = false
    drawToolThat._drawType = ''
    drawToolThat._coordinates = []
    drawToolThat._drawFeature = null

    setTimeout(() => {
      toggleDoubleZoom(drawToolThat._map)
      drawToolThat._editTool.toggleEdit(true)
    }, 500)
  }

  // 删除绘制状态feature
  _removeTempFeature () {
    if (this._drawFeature) {
      this._vectorSource.removeFeature(this._drawFeature)
      this._drawFeature = null
    }
  }

  // 添加点
  _addPoint2Map () {
    const featureJson = {
      geometry: new Point(this._coordinates[0]),
      geometryType: GEOMETRYTYPE.POINT,
      id: this._drawId
    }
    const feature = new Feature(featureJson)
    this._vectorSource.addFeature(feature)
    // 绘制完成后的回调
    drawToolThat._options.drawEnd.call(this, feature)
  }

  // 添加线
  _addLine2Map (coordinates, isTemp = false) {
    this._removeTempFeature()
    coordinates = filterDuplicatePoints(coordinates)
    const featJson = {
      geometry: new LineString(coordinates),
      geometryType: GEOMETRYTYPE.LINESTRING
    }
    if (!isTemp) featJson.id = this._drawId
    this._drawFeature = new Feature(featJson)
    this._vectorSource.addFeature(this._drawFeature)
  }

  // 添加面
  _addPolygon2Map (coordinates, isTemp = false) {
    this._removeTempFeature()
    coordinates = filterDuplicatePoints(coordinates)
    const featJson = {
      geometry: new Polygon([coordinates]),
      geometryType: GEOMETRYTYPE.POLYGON
    }
    if (!isTemp) featJson.id = this._drawId
    this._drawFeature = new Feature(featJson)
    this._vectorSource.addFeature(this._drawFeature)
  }

  // 添加矩形
  _addRectangle2Map (coordinates, isTemp = false) {
    this._removeTempFeature()
    const featJson = {
      geometry: new Polygon([coordinates]),
      geometryType: GEOMETRYTYPE.RECTANGLE
    }
    if (!isTemp) featJson.id = this._drawId
    this._drawFeature = new Feature(featJson)
    this._vectorSource.addFeature(this._drawFeature)
  }

  // 添加圆
  _addCircle2Map (center, point, isTemp = false) {
    this._removeTempFeature()
    const [x0, y0] = center
    const [x1, y1] = point
    const dx = x0 - x1
    const dy = y0 - y1
    const radius = Math.sqrt(dx ** 2 + dy ** 2)
    const coords = getCircleCoords(center, radius)
    const featJson = {
      geometry: new Polygon([coords]),
      geometryType: GEOMETRYTYPE.CIRCLE,
      point: point,
      center: center,
      pointOrigin: point,
      centerOrigin: center
    }
    if (!isTemp) featJson.id = this._drawId
    this._drawFeature = new Feature(featJson)
    this._vectorSource.addFeature(this._drawFeature)
  }
}

export default DrawTool
